package cn.ulyer.core.secure.authority;

import cn.ulyer.common.constants.StatusEnum;
import cn.ulyer.common.jpa.entity.Permission;
import cn.ulyer.common.jpa.entity.QPermission;
import cn.ulyer.common.security.authority.AuthorityProvider;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.PostConstruct;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
public class CacheAuthorityProvider implements AuthorityProvider {

    final static List<Permission> CACHE = new CopyOnWriteArrayList<>();

    @Autowired
    private JPAQueryFactory queryFactory;

    private final ReentrantLock reloadLock = new ReentrantLock();

    @PostConstruct
    public void initAuthorities() {
        reload();
    }

    private void reload() {
        QPermission qPermission = QPermission.permission;
        Collection<Permission> permissions = queryFactory.select(
                        Projections.fields(qPermission,
                                qPermission.permissionType,
                                qPermission.authStrategy,
                                qPermission.permValue,
                                qPermission.id,
                                qPermission.url,
                                qPermission.createTime)
                ).from(qPermission)
                .where(qPermission.permissionType.eq(Permission.PermissionType.API)
                        , qPermission.status.eq(StatusEnum.ENABLE.status())
                ).fetch();
        try {
            reloadLock.lock();
            CACHE.clear();
            log.info("refresh cache authorities-----------------");
            CACHE.addAll(permissions);
        } finally {
            reloadLock.unlock();
        }

    }


    @Override
    public List<Permission> providerPermissions() {
        return CACHE;
    }


    @Override
    public boolean clear() {
        CACHE.clear();
        return true;
    }

    @Override
    public void refresh() {
        this.reload();
        ;
    }


}
